/* 
 * File:   Nivel.cpp
 * Author: agu
 * 
 * Created on 7 de junio de 2014, 18:54
 */

#include "editor_Nivel.h"
#include <vector>
#include <iostream>
#include <algorithm>
#define CHICO "Chico"
#define MEDIANO "Mediano"
#define GRANDE "Grande"
#define SIZE_CHICO 5
#define SIZE_MEDIANO 10
#define SIZE_GRANDE 15
using std::vector;

Nivel::Nivel() {
    this->id = 0;
    this->width = 0;
    this->height = 0;
    this->difficult = "Facil";
    this->spawn = "abcde";
    this->name = "";
    this->tileMap = "";
    this->minPlayers = 1;
    this->numPlants = 0;
    this->numPlayers = 0;
}

Nivel::Nivel(unsigned int id, const string diff, int minPlayer) {
    this->id = id;
    this->difficult = diff;
    this->width = 0;
    this->height = 0;
    this->name = "";
    this->tileMap = "";
    this->spawn = "abcde";
    this->minPlayers = minPlayer;
    this->numPlants = 0;
    this->numPlayers = 0;
    this->numZombieB = 0;
    this->numZombieR = 0;
    this->numZombieG = 0;
}

Nivel::~Nivel() {
}

unsigned int Nivel::getId() {
    return this->id;
}

string Nivel::getName() {
    return this->name;
}

string Nivel::getTileMap() {
    return this->tileMap;
}

void Nivel::incrementMapWidth() {
    this->width++;
}

void Nivel::incrementMapHeight() {
    this->height++;
}

bool Nivel::checkHeight() {
    if ((this->height >= this->minHeight) && (this->height <= this->maxHeight))
        return true;
    return false;
}

bool Nivel::checkWidth() {
    if ((this->width >= this->minWidth) && (this->width <= this->maxWidth))
        return true;
    return false;
}

bool Nivel::checkDimension() {
    return (this->checkWidth() && this->checkHeight());
}

unsigned int Nivel::getMapWidth() {
    return this->width;
}

unsigned int Nivel::getMapHeight() {
    return this->height;
}

bool Nivel::validate(string& msjError) {
    //Agregar validaciones de cantidad de personajes, enemigos, etc.
    if (!this->validateNumberEnemys()) {
        msjError = "Numero de enemigos invalido";
        return false;
    }
    if (!this->validateNumberPlants()) {
        msjError = "Numero de plantas invalido";
        return false;
    }
    if (!this->validateNumberPlayers()) {
        msjError = "Numero de jugadores invalido";
        return false;
    }
    msjError = "";
    return true;
}

void Nivel::setMap(Gtk::Grid *grid) {
    string map;
    vector<Gtk::Widget*> cells = grid->get_children();
    for (unsigned int i = 0; i < cells.size(); i++) {
        Gtk::Image* img = (Gtk::Image*) cells.at(i);
        string imageName(img->property_file().get_value().c_str());
        map.append(this->nameToCode(imageName.erase(0, 16)));

    }
    std::reverse(map.begin(), map.end());

    this->tileMap = transformMap(map);
}

string Nivel::transformMap(const string map) {
    string transformMap = "";
    unsigned int tam = sqrt(map.size());
    vector< vector<string> > prin;
    for (unsigned int i = 0; i < tam; i++) {
        vector<string> vectorI;
        for (unsigned int j = 0; j < tam; j++) {
            vectorI.push_back(string(1, map.at(i * tam + j)));
        }
        prin.push_back(vectorI);
    }
    for (unsigned int i = 0; i < prin.size(); i++) {
        std::reverse(prin.at(i).begin(), prin.at(i).end());
    }
    for (unsigned int i = 0; i < prin.size(); i++) {
        for (unsigned int j = 0; j < prin.at(i).size(); j++) {
            transformMap.append(string(prin.at(i).at(j)));
        }

    }
    return transformMap;

}

void Nivel::setName(const string name) {
    this->name = name;
}

void Nivel::save() {
}

void Nivel::reset() {
    this->numZombieG = 0;
    this->numZombieB = 0;
    this->numZombieR = 0;
    this->numPlayers = 0;
    this->numPlants = 0;
}

string Nivel::nameToCode(const string name) {
    string code;
    if (name.compare("floor.png") == 0) {
        code = "0";
    }
    if (name.compare("box.png") == 0) {
        code = "1";
    }
    if (name.compare("boxEnemy.png") == 0) {
        code = "2";
        this->numZombieG++;
    }
    if (name.compare("metal.png") == 0) {
        code = "3";
    }
    if (name.compare("zombieGreen.png") == 0) {
        code = "4";
        this->numZombieG++;
    }

    if (name.compare("zombieBlue.png") == 0) {
        code = "5";
        this->numZombieB++;
    }
    if (name.compare("zombieRed.png") == 0) {
        code = "6";
        this->numZombieR++;
    }
    if (name.compare("friend.png") == 0) {
        code = "7";
        this->numPlants++;
    }
    if (name.compare("player.png") == 0) {
        code = this->spawn.at(numPlayers);
        this->numPlayers++;
    }
    return code;
}

void Nivel::setMapWidth(unsigned int width) {
    this->width = width;
}

void Nivel::setMapHeight(unsigned int height) {
    this->height = height;
}

bool Nivel::validateNumberEnemys() {
    
    int numEnemys = this->numZombieB + this->numZombieG + this->numZombieR;
    if ((numEnemys >= this->minEnemys) && (numEnemys <= this->maxEnemys))
        return true;
    return false;
}

bool Nivel::validateNumberPlants() {
    if ((this->numPlants >= this->minPlants) && (this->numPlants <= this->maxPlants))
        return true;
    return false;
}

bool Nivel::validateNumberPlayers() {
    if ((this->numPlayers >= this->minPlayers) && (this->numPlayers <= this->maxPlayers))
        return true;
    return false;
}

vector<string> Nivel::getInfo() {
    vector<string> levelInfo;
    levelInfo.push_back(std::to_string(this->id));
    levelInfo.push_back(this->name);
    levelInfo.push_back(std::to_string(this->numZombieG));
    levelInfo.push_back(std::to_string(this->numZombieB));
    levelInfo.push_back(std::to_string(this->numZombieR));
    levelInfo.push_back(std::to_string(this->numPlants));
    levelInfo.push_back(std::to_string((int) sqrt(this->tileMap.size())));
    levelInfo.push_back(this->tileMap);
    return levelInfo;
}

void Nivel::setSizeMap(const string sizeName) {
    if (sizeName.compare("Chico") == 0) {
        this->width = this->height = SIZE_CHICO;
    }
    if (sizeName.compare("Mediano") == 0) {
        this->width = this->height = SIZE_MEDIANO;
    }
    if (sizeName.compare("Grande") == 0) {
        this->width = this->height = SIZE_GRANDE;
    }
}

void Nivel::setTileMap(const string tileMap) {
    this->tileMap = tileMap;
}

void Nivel::loadGridMap(Gtk::Grid * grid) {

    string mapaOrig = this->transformMap(this->tileMap);
    std::reverse(mapaOrig.begin(), mapaOrig.end());
    unsigned int sizeMap = sqrt(mapaOrig.size());
    unsigned int k=0;
    for (unsigned int i = 0; i <sizeMap; i++) {
        //Recorro todas las columnas
        for (unsigned int j = 0; j < sizeMap; j++) {
            Gtk::Image* img = Gtk::manage(new Gtk::Image);
            string code(1,mapaOrig.at(k));
            img->set(this->codeToName(code)); //Emprolijar                
            grid->attach(*img, i, j, 1, 1);
            k++;
        }
    }


}

string Nivel::codeToName(const string code) {
    string name = "gladeInterfaces/";
    if (code.compare("0") == 0) {
        name += "floor.png";
    }
    if (code.compare("1") == 0) {
        name += "box.png";
    }
    if (code.compare("2") == 0) {
        name += "boxEnemy.png";
        this->numZombieG++;
    }
    if (code.compare("3") == 0) {
        name += "metal.png";
    }
    if (code.compare("4") == 0) {
        name += "zombieGreen.png";
        this->numZombieG++;
    }

    if (code.compare("5") == 0) {
        name += "zombieBlue.png";
        this->numZombieB++;
    }
    if (code.compare("6") == 0) {
        name += "zombieRed.png";
        this->numZombieR++;
    }
    if (code.compare("7") == 0) {
        name += "friend.png";
        this->numPlants++;
    }
    if ((code.compare("a") == 0) || (code.compare("b") == 0) || (code.compare("c") == 0) || (code.compare("d") == 0) || (code.compare("e") == 0)) {
        name += "player.png";
        this->numPlayers++;
    }
    return name;
}